package greenhouse_allocation_record

import (
	rich_err "app/error"
	"app/models"
	"app/service"
	"app/service/orders"
	"errors"
	"math"
	"strconv"

	"github.com/jinzhu/gorm"

	"github.com/gin-gonic/gin"
)

func Gets(context *gin.Context) ([]*models.GreenhouseAllocationRecordDetail, *models.Pager, *rich_err.RichError) {
	base := models.Orm.Model(&models.GreenhouseAllocationRecord{}).
		Select("greenhouse_allocation_record.*, goadmin_users.name as manager_name,  greenhouse.name as greenhouse_name, orders.name as orders_name").
		Joins("LEFT JOIN goadmin_users ON greenhouse_allocation_record.manager_id = goadmin_users.id").
		Joins("LEFT JOIN greenhouse ON greenhouse_allocation_record.greenhouse_id = greenhouse.id").
		Joins("LEFT JOIN orders ON greenhouse_allocation_record.order_id = orders.id")

	if greenhouseManagerIDStr, ok := context.GetQuery("greenhouse_manager_id"); ok {
		greenhouseManagerID, _ := strconv.Atoi(greenhouseManagerIDStr)
		var greenhouseID []int
		err := models.Orm.Table("greenhouse").
			Select("id").
			Where("manager_id = ?", greenhouseManagerID).
			Pluck("id", &greenhouseID).Error
		if err != nil {
			return nil, nil, rich_err.NewError(rich_err.RequestInvalid, err)
		}
		if len(greenhouseID) == 0 {
			return []*models.GreenhouseAllocationRecordDetail{}, &models.Pager{Count: 0, Index: 1, Size: 0}, nil
		}
		base = base.Where("greenhouse_id in (?) ", greenhouseID)
	}

	results, pager, err := service.GetDetails[models.GreenhouseAllocationRecordDetail](context, base, models.GreenhouseAllocationRecord{}.TableName(), map[string]string{"manager_name": "goadmin_users.name", "greenhouse_name": "greenhouse.name", "orders_name": "orders.name"})

	if err != nil {
		return nil, nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	return results, pager, nil
}

func Get(id string) (*models.GreenhouseAllocationRecordDetail, *rich_err.RichError) {
	base := models.Orm.Model(&models.GreenhouseAllocationRecord{}).
		Select("greenhouse_allocation_record.*, goadmin_users.name as manager_name,  greenhouse.name as greenhouse_name, orders.name as orders_name").
		Joins("LEFT JOIN goadmin_users ON greenhouse_allocation_record.manager_id = goadmin_users.id").
		Joins("LEFT JOIN greenhouse ON greenhouse_allocation_record.greenhouse_id = greenhouse.id").
		Joins("LEFT JOIN orders ON greenhouse_allocation_record.order_id = orders.id")

	result, err := service.GetDetail[models.GreenhouseAllocationRecordDetail](id, base)

	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	return result, nil
}

func Create(context *gin.Context) (*models.GreenhouseAllocationRecordDetail, *rich_err.RichError) {
	req := new(models.GreenhouseAllocationRecordCore)
	if err := context.ShouldBindJSON(req); err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	data := models.GreenhouseAllocationRecord{GreenhouseAllocationRecordCore: *req}
	if data.Quantity == 0 {
		data.Quantity = data.TrayNumber * data.UnitNumber
	}
	result := models.Orm.Create(&data)
	if result.Error != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}
	// 更新订单成已分棚
	if err := models.Orm.Model(&models.Orders{}).Where("id = ?", req.OrderID).Update("order_status", 5).Error; err != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, err)
	}
	return Get(strconv.Itoa(data.ID))
}

func Update(context *gin.Context) (*models.GreenhouseAllocationRecordDetail, *rich_err.RichError) {
	req := new(models.GreenhouseAllocationRecordDelta)
	if err := context.ShouldBindJSON(req); err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}

	data, err := service.Get[models.GreenhouseAllocationRecord](context)
	if err != nil {
		return nil, rich_err.NewError(rich_err.RequestInvalid, err)
	}
	if req.GreenhouseID != nil {
		data.GreenhouseID = int(math.Round(req.GreenhouseID.(float64)))
	}
	if req.OrderID != nil {
		data.OrderID = int(math.Round(req.OrderID.(float64)))
	}
	if req.ManagerID != nil {
		data.ManagerID = int(math.Round(req.ManagerID.(float64)))
	}
	if req.TrayNumber != nil {
		data.TrayNumber = int(math.Round(req.TrayNumber.(float64)))
	}
	if req.UnitNumber != nil {
		data.UnitNumber = int(math.Round(req.UnitNumber.(float64)))
	}
	if req.Quantity != nil {
		data.Quantity = int(math.Round(req.Quantity.(float64)))
	} else {
		data.Quantity = data.TrayNumber * data.UnitNumber
	}
	if req.Remark != nil {
		data.Remark = req.Remark.(string)
	}
	result := models.Orm.Save(data)
	if result.Error != nil {
		return nil, rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}
	return Get(strconv.Itoa(data.ID))
}

func Delete(context *gin.Context) *rich_err.RichError {
	data, err := service.Get[models.GreenhouseAllocationRecord](context)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil
		}
		return rich_err.NewError(rich_err.RequestInvalid, err)
	}
	result := models.Orm.Delete(data)
	if result.Error != nil {
		return rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}

	// 联动删除其他项
	conditions := map[string]interface{}{"greenhouse_allocation_id = ?": data.ID}
	richErr := service.DeleteByConditions[models.SeedbedAllocationRecord](conditions)
	if richErr != nil {
		return richErr
	}
	richErr = service.DeleteByConditions[models.SeedbedAllocationBatchRecord](conditions)
	if richErr != nil {
		return richErr
	}
	// 由于删除了 SeedbedAllocationRecord,SeedbedAllocationBatchRecord 苗床分配记录, 需要更新orders表的 已分配苗床数量
	var orderIDs []int
	err = models.Orm.Model(&models.Orders{}).Pluck("order_id", &orderIDs).Error
	if err != nil {
		return rich_err.NewError(rich_err.DatabaseFailed, result.Error)
	}

	for _, orderID := range orderIDs {
		err = orders.UpdateAllocatedSeedbedQuantity(orderID)
		if err != nil {
			return rich_err.NewError(rich_err.DatabaseFailed, err)
		}
	}
	return nil
}

func UpdateAllocatedSeedbedQuantity(greenhouseAllocationID int) error {
	var allocatedSeedbedQuantity int
	if err := models.Orm.Model(&models.SeedbedAllocationBatchRecord{}).Where("greenhouse_allocation_id = ?", greenhouseAllocationID).Select("COALESCE(sum(quantity), 0)").Row().Scan(&allocatedSeedbedQuantity); err != nil {
		return err
	}

	if err := models.Orm.Model(&models.GreenhouseAllocationRecord{}).Where("id = ?", greenhouseAllocationID).Update("allocated", allocatedSeedbedQuantity).Error; err != nil {
		return err
	}

	return nil
}
